#ifndef __JNGLOADER_H__
#define __JNGLOADER_H__

/*
JNG image loading library v1.0.1
(c) 2012 Aleksander Similyetov (elmm00@gmail.com)

Changelog:
1.0.1
- simple memory tracking
- fixed memory leaks
- jng_cleanup call jng_finish_decode if decoder was not destroyed before cleanup
*/

#include <stdlib.h>

/************************************************************************/
/* Constants                                                            */
/************************************************************************/

typedef enum
{
	JNG_OK	= 0,
	JNG_ERR_NOT_ENOUGH_MEM = 1,
	JNG_ERR_CORRUPTED_HANDLE_DATA,
	JNG_ERR_INVALID_FUNCTION_ARGUMENT,
	
	JNG_ERR_READ_CHUNK_HEADER,
	JNG_ERR_READ_CHUNK_DATA,
	JNG_ERR_READ_SIGNATRUE,
	JNG_ERR_INCORRECT_SIGNATRUE,
	JNG_ERR_CHUNK_CRC,
	JNG_ERR_CHUNKS_ORDER,
	JNG_ERR_CHUNKS_COUNT,
	JNG_ERR_CHUNK_ALPHA_TYPE,
	JNG_ERR_IMAGE_READ_STATE,
	
	JNG_ERR_DECODE_ALREADY_STARTED,
	JNG_ERR_DECODE_NOT_STARTED,
	JNG_ERR_DECODE_END_OF_IMAGE,

	JNG_ERR_NO_SUCH_JDAT_CHUNK_TYPE,
	JNG_ERR_CHUNK_UNSUPPORTED_JPEG_FORMAT,

	JNG_ERR_DECODE_JPEG_COLORS,
	JNG_ERR_COLOR_DIMENTIONS_MISMATCH,
	JNG_ERR_ALPHA_DIMENTIONS_MISMATCH,
	JNG_ERR_JPEG_DECOMPRESSION,
	JNG_ERR_JPEG_ALPHA_FORMAT,
	JNG_ERR_UNSUPPORTED_ALPHA_INTERLACE,

	JNG_ERR_ZLIB_INFLATE_INIT,
	JNG_ERR_ZLIB_INFLATE,
	JNG_ERR_ZLIB_INFLATE_END_OF_STREAM,
	JNG_ERR_END_OF_DATA,

	JNG_ERR_NO_ALPHA_CHANNEL,

} JNG_ERRORS;

typedef enum 
{
	JNG_JPEG_SRC_DEFAULT = 0,
	JNG_JPEG_SRC_8BITS = 1,
#ifdef JNG_JPEG_12_BITS
	JNG_JPEG_SRC_12BITS = 2
#endif/*JNG_JPEG_12_BITS*/
} JNG_JPEG_SRC_TYPE;

typedef enum 
{
	JNG_OUT_BITS_DEFAULT = 0,
	JNG_OUT_BITS_8 = 8,
	JNG_OUT_BITS_16 = 16
} JNG_OUT_BITS_PER_SAMPLE;

typedef enum 
{
	JNG_FLAG_CRC_CRITICAL = 1,
	JNG_FLAG_CRC_ANCILLARY = 2,
	JNG_FLAG_STORE_ANCILLARY_CHUNKS = 4,
	JNG_FLAGS_DEFAULT = JNG_FLAG_CRC_CRITICAL | JNG_FLAG_CRC_ANCILLARY,
} JNG_FLAGS;

typedef enum
{
	JNG_GREY = 1,
	JNG_GREY_ALPHA,
	JNG_COLOR,
	JNG_COLOR_ALPHA
} JNG_COLOR_COMPONENTS;

typedef enum
{
	JNG_GRAYSCALE = 1,
	JNG_YCbCr,
	JNG_RGB,
	JNG_CMYK,
	JNG_YCCK
} JNG_COLOR_SPACE;

#define JNG_TRUE	1
#define JNG_FALSE	0

/************************************************************************/
/* Simple types                                                         */
/************************************************************************/

typedef int jng_bool;

struct _jng_info;
typedef struct _jng_info* jng_handle;

/************************************************************************/
/* Structures                                                           */
/************************************************************************/

#pragma pack(push)
#pragma pack(1)

typedef struct _jng_chunk_header
{
	unsigned long dataLength;	/*chunk data size (not including type and crc)*/
	union _chunkType			/*chunk id*/
	{
		unsigned long longVal;
		unsigned char charVal[4];
	} chunkType;
} jng_chunk_header, *pjng_chunk_header;

typedef struct _jng_chunk
{
	jng_chunk_header header;
	unsigned char data[];
} jng_chunk, *pjng_chunk;

#pragma pack(pop)

/************************************************************************/
/* typedef for callbacks                                                */
/************************************************************************/

typedef void* (*jng_alloc)(size_t size);
typedef void (*jng_free)(void* ptr);

typedef size_t (*jng_readproc)(jng_handle info, void* buffer, size_t size);
typedef size_t (*jng_skipproc)(jng_handle info, size_t size);

/*Warning! ChunkName is passed in network byte order!*/
typedef void (*jng_errorproc)(jng_handle handle, int errorCode, unsigned long chunkName, unsigned long chunkSeq, const char* erorText);

/************************************************************************/
/* JNG image loading API                                                */
/************************************************************************/

/*Create handle to JNG image from data buffer, setup callbacks and check JNG signature*/
jng_handle jng_create_from_data(void* userData, const void* data, size_t size, jng_alloc allocPtr, jng_free freePtr, jng_errorproc errorPtr, unsigned long flags);
/*Create handle to JNG image from stream, setup callbacks and check JNG signature*/
jng_handle jng_create_from_stream(void* userData, jng_readproc readPtr, jng_skipproc skipPtr, jng_alloc allocPtr, jng_free freePtr, jng_errorproc errorPtr, unsigned long flags);
/*Cleanup function. It will free all resources, associated with jng_handle passed. After cleanup jng_handle becomes invalid.*/
void jng_cleanup(jng_handle handle);
/*Return userData, passed to jng_create_ functions*/
void* jng_get_user_data(jng_handle handle);
/*Read and store all chunks that required to decode image*/
jng_bool jng_read(jng_handle handle);


/*Warining! You can querry image parameters only after successful call to jng_read()*/

/*Return image width (or 0 on error)*/
unsigned long jng_get_image_width(jng_handle handle);
/*Return image height (or 0 on error)*/
unsigned long jng_get_image_height(jng_handle handle);
/*Return 1 if image contains alpha*/
int jng_get_image_alpha_components(jng_handle handle);
/*Return color components type of loaded image (value from enumeration JNG_COLOR_COMPONENTS or 0 as error code)*/
JNG_COLOR_COMPONENTS jng_get_image_components(jng_handle handle);

/*Can return 0, 1, 2, 4, 8, 16, or 0 as error or in case image does not have alpha*/
int jng_get_alpha_channel_bits(jng_handle handle);
/*Return available bits per sample for JPEG part of image. Possible return values - 8, 12, 20 (8 + 12) or 0 as error code*/
int jng_get_colors_channel_bits(jng_handle handle);

/*Setting and getting decoder output parameters*/
/*Next two functions are used to setup output per channel bits depth. By default output bit depth is equals to input bit depth.*/
jng_bool jng_set_out_alpha_channel_bits(jng_handle handle, JNG_OUT_BITS_PER_SAMPLE sampleDepth);
jng_bool jng_set_out_color_channel_bits(jng_handle handle, JNG_OUT_BITS_PER_SAMPLE sampleDepth);
/*Return number of bits in output alpha channel. Possible return values 1, 2, 4, 8, 16 or 0 - if error occurred or alpha channel not present*/
int jng_get_out_alpha_channel_bits(jng_handle handle);
/*Return number of bits per channel in output colors. Possible values 16, 12, 8 or 0 - if error occurred.*/
int jng_get_out_color_channel_bits(jng_handle handle);
/*Return number of bytes, required to fit alpha channel*/
int jng_get_out_alpha_channel_bytes(jng_handle handle);
/*Return number of bytes, required to fit all color channels*/
int jng_get_out_color_channel_bytes(jng_handle handle);

/*Set output color space (see JNG_COLOR_SPACE). JNG_RGB is default*/
jng_bool jng_set_out_color_space(jng_handle handle, JNG_COLOR_SPACE space);
/*Return 1 if image contain alpha channel*/
int jng_get_out_alpha_components_num(jng_handle handle);
/*Return number of color components in output space (this value does NOT depend on presence of alpha channel)*/
int jng_get_out_color_components_num(jng_handle handle);
/*Return number of pixel components in output space (this value depends on jng_set_color_space and presence of alpha channel)*/
int jng_get_out_pixel_components_num(jng_handle handle);

jng_bool jng_set_color_jpeg_src_type(jng_handle handle, JNG_JPEG_SRC_TYPE jpgSrcType);
JNG_JPEG_SRC_TYPE jng_get_jpeg_src_type(jng_handle handle);

/*Set pixel format as Alpha-Color (default Color-Alpha)*/
jng_bool jng_set_alpha_before_color(jng_handle handle);

/*Start decoding. Warning! Currently you can pass only JNG_JPEG_DEFAULT and JNG_JPEG8  as jngColorsSource parameter.*/
jng_bool jng_start_decode(jng_handle handle);
/*Read one line from image. Warinng - width and hight of image are limited to 65535 due to JPEG limitations. Return JNG_FALSE as error. */
jng_bool jng_read_scanline(jng_handle handle, void* row);
/*Read scanlines into array. Return # of read scanlines or 0 if error occured.*/
size_t jng_read_scanlines(jng_handle handle, void* rows[], size_t scanlinesNum);

/*Call this function to finish decoding process (also it will be called in jng_cleanup if decode hasn't been finished before cleanup process).*/
void jng_finish_decode(jng_handle handle);


#endif//__JNGLOADER_H__